package cn.demoncat.util.hazelcast.util;

import java.util.function.BiPredicate;

import javax.annotation.Resource;

import org.springframework.stereotype.Component;

import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.core.IAtomicLong;
import com.hazelcast.core.IAtomicReference;
import com.hazelcast.core.IFunction;
import com.hazelcast.core.IList;
import com.hazelcast.core.IMap;
import com.hazelcast.core.IQueue;
import com.hazelcast.core.ISemaphore;
import com.hazelcast.core.ISet;
import com.hazelcast.core.ITopic;
import com.hazelcast.cp.lock.FencedLock;
import com.hazelcast.flakeidgen.FlakeIdGenerator;
import com.hazelcast.transaction.TransactionContext;

/**
 * Hazelcast 分布式JVM缓存工具
 * 
 * @author 延晓磊
 *
 * @since 2020年2月18日
 */
@Component
public class HzUtil {
	
	/**
	 * HazelcastInstance 实例：客户端/服务端
	 */
	@Resource
	private HazelcastInstance hzInstance;
	
	/**
	 * 获取HazelcastInstance
	 * 
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2020年2月18日
	 */
	public HazelcastInstance getInstance() {
		return hzInstance;
	}
	
	/**
	 * 获取Map
	 * 
	 * @param name
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2020年2月18日
	 */
	public <K, V> IMap<K, V> getMap(String name){
		return hzInstance.getMap(name);
	}
	
	/**
	 * 获取Map.Value
	 * 
	 * @param name
	 * @param key
	 * @return value
	 * 
	 * @author 延晓磊
	 *
	 * @since 2020年2月18日
	 */
	public <K, V> V getByMap(String name, K key){
		IMap<K, V> map = this.getMap(name);
		return map.get(key);
	}
	
	/**
	 * 设置Map.Value
	 * 
	 * @param name
	 * @param key
	 * @param value
	 * 
	 * @return 之前的value，非null表示替换
	 * 
	 * @author 延晓磊
	 *
	 * @since 2020年2月18日
	 */
	public <K, V> V setMap(String name, K key, V value){
		IMap<K, V> map = this.getMap(name);
		return map.put(key, value);
	}
	
	/**
	 * 获取Queue
	 * 
	 * @param name
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2020年2月18日
	 */
	public <E> IQueue<E> getQueue(String name){
		return hzInstance.getQueue(name);
	}
	
	/**
	 * 获取Topic(订阅主题，注册监听器)
	 * 
	 * @param name
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2020年2月18日
	 */
	public <E> ITopic<E> getTopic(String name){
		return hzInstance.getTopic(name);
	}
	
	/**
	 * 获取List
	 * 
	 * @param name
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2020年2月18日
	 */
	public <E> IList<E> getList(String name){
		return hzInstance.getList(name);
	}
	
	/**
	 * 获取Set
	 * 
	 * @param name
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2020年2月18日
	 */
	public <E> ISet<E> getSet(String name){
		return hzInstance.getSet(name);
	}
	
	/**
	 * 获取ID生成器
	 * 
	 * @param name
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2020年2月18日
	 */
	public FlakeIdGenerator getIdGenerator(String name) {
		return hzInstance.getFlakeIdGenerator(name);
	}

    /**
     * 获取IAtomicLong
     * 
     * @param name
     * @return
     * 
     * @author 延晓磊
     *
     * @since 2020年2月18日
     */
    public IAtomicLong getAtomicLong(String name) {
    	return hzInstance.getCPSubsystem().getAtomicLong(name);
    }

    /**
     * 获取AtomicReference
     * 
     * @param name
     * @return
     * 
     * @author 延晓磊
     *
     * @since 2020年2月18日
     */
    public <E> IAtomicReference<E> getAtomicReference(String name){
    	return hzInstance.getCPSubsystem().getAtomicReference(name);
    }
    
    /**
     * 获取AtomicReference的值
     * 
     * @param name
     * @return
     * 
     * @author 延晓磊
     *
     * @since 2020年2月18日
     */
    public <T>T getByAtomicReference(String name) {
    	IAtomicReference<T> atomic = getAtomicReference(name);
    	return atomic.get();
    }
    
    /**
     * 安全获取AtomicReference的值
     * 
     * @param name	
     * @param fn	获取函数：(当前值) -> 结果值
     * 
     * @return	结果值
     * 
     * @author 延晓磊
     *
     * @since 2020年2月18日
     */
    public <T>T getAtomicReference(String name, IFunction<T, T> fn) {
    	IAtomicReference<T> atomic = getAtomicReference(name);
    	// 根据函数获取结果（对当前值运算），不更新
    	return atomic.apply(fn);
	}
    
    /**
     * 设置AtomicReference的值
     * 
     * @param name
     * @param value
     * @return
     * 
     * @author 延晓磊
     *
     * @since 2020年2月18日
     */
    public <T>T setAtomicReference(String name, T value) {
    	IAtomicReference<T> atomic = getAtomicReference(name);
    	// 直接设置
    	atomic.set(value);
		return value;
	}
    
    /**
     * 安全设置AtomicReference的值
     * 
     * @param name	
     * @param fn	修改函数：(当前值) -> 结果值
     * 
     * @return	结果值
     * 
     * @author 延晓磊
     *
     * @since 2020年2月18日
     */
    public <T>T setAtomicReference(String name, IFunction<T, T> fn) {
    	IAtomicReference<T> atomic = getAtomicReference(name);
    	// 根据函数设置（对当前值运算），返回新值
    	return atomic.alterAndGet(fn);
	}
    
    /**
     * 乐观锁设置AtomicReference的值
     * 
     * @param name
     * @param value		更新值
	 * @param predicate 判断是否需要更改的函数：(当前值，更新值) -> true/false
	 * 
	 * @return 最新值（true更新值/false当前值）
	 * 
	 * @author 延晓磊
	 *
	 * @since 2020年2月16日
	 */
    public <T>T setAtomicReference(String name, T value, BiPredicate<T,T> predicate) {
    	IAtomicReference<T> atomic = getAtomicReference(name);
    	// 递归获取当前值，判断为true时更新，为false时退出
    	return setAtomicReference(atomic, value, predicate);
	}
    
    /**
	 * 乐观锁更新
	 * 
	 * @param atomic
	 * @param value		更新值
	 * @param predicate 判断是否需要更改的函数：(当前值，更新值) -> true/false
	 * 
	 * @return 最新值（true更新值/false当前值）
	 * 
	 * @author 延晓磊
	 *
	 * @since 2020年2月16日
	 */
	public <T>T setAtomicReference(IAtomicReference<T> atomic, T value, BiPredicate<T,T> predicate) {
		// 当前值
		T curr = atomic.get();
		// 判断
		if (curr == null || predicate.test(curr, value)) {
			// 当前值为空，判断可以更改
			if (atomic.compareAndSet(curr, value)) {
				// 更新成功
				return value;
			}else {
				// 递归
				return setAtomicReference(atomic, value, predicate);
			}
		}else {
			// 当前值非空，判断无需更改
			return curr;
		}
	}
	
    /**
     * 开启事务
     * 
     * @return
     * 
     * @author 延晓磊
     *
     * @since 2020年2月18日
     */
    public TransactionContext beginTransaction() {
    	TransactionContext transaction = hzInstance.newTransactionContext();
		transaction.beginTransaction();
		return transaction;
    }
    
    /**
     * 提交事务
     * 
     * @param transaction
     * 
     * @author 延晓磊
     *
     * @since 2020年2月18日
     */
    public void commitTransaction(TransactionContext transaction) {
		transaction.commitTransaction();
    }
    
    /**
     * 回滚事务
     * 
     * @param transaction
     * 
     * @author 延晓磊
     *
     * @since 2020年2月18日
     */
    public void rollbackTransaction(TransactionContext transaction) {
		transaction.rollbackTransaction();
    }
    
    /**
     * 事务操作
     * 
     * @param run
     * 
     * @author 延晓磊
     *
     * @since 2020年2月18日
     */
    public void transaction(Runnable run) {
    	// 开启事务
    	TransactionContext transaction = beginTransaction();
    	try {
    		// 执行操作
    		run.run();
    		// 提交事务
    		commitTransaction(transaction);
		} catch (RuntimeException e) {
			// 回滚事务
			rollbackTransaction(transaction);
			throw e;
		}
    }

    /**
     * 获取锁
     * 
     * @param name
     * @return
     * 
     * @author 延晓磊
     *
     * @since 2020年2月18日
     */
    public FencedLock getLock(String name) {
    	return hzInstance.getCPSubsystem().getLock(name);
    }
    
    /**
     * 锁操作
     * 
     * @param name
     * @param run
     * 
     * @author 延晓磊
     *
     * @since 2020年2月18日
     */
    public void lock(String name, Runnable run) {
    	// 获取锁
    	FencedLock lock = getLock(name);
    	// 加锁
    	lock.lock();
    	try {
    		// 执行操作
    		run.run();
		} finally {
			// 释放锁
			lock.unlock();
		}
    }
    
    /**
     * 锁操作
     * 
     * @param name
     * @param run
     * 
     * @return false表示未获取锁 
     * 
     * @author 延晓磊
     *
     * @since 2020年2月18日
     */
    public boolean tryLock(String name, Runnable run) {
    	// 获取锁
    	FencedLock lock = getLock(name);
    	// 加锁
    	if (lock.tryLock()) {
    		try {
    			// 执行操作
    			run.run();
    		} finally {
    			// 释放锁
    			lock.unlock();
    		}
    		return true;
		}
    	return false;
    }
    
    /**
     * 获取信号量（控制并发线程数）
     * 
     * @param name
     * @return
     * 
     * @author 延晓磊
     *
     * @since 2020年2月18日
     */
    public ISemaphore getSemaphore(String name) {
    	return hzInstance.getCPSubsystem().getSemaphore(name);
    }
    
    
    
	
    
}
